﻿using AutoMapper;
using Morin.Services;
using Morin.Shared.Models;
using Morin.Shared.Parameters;
using Morin.Wpf.Adapters;
using Morin.Wpf.Common;
using Morin.Wpf.Messages;
using Morin.Wpf.ViewModels.Players;
using Stylet;
using StyletIoC;

namespace Morin.Wpf.ViewModels.Videos;

public class SearchViewModel(
    IContainer container,
    IAppService appService,
    ISourceProtocolAdapter sourceProtocolAdapter,
    IEventAggregator eventAggregator,
    IMapper mapper,
    IApiService apiService,
    IWindowManager windowManager) : Screen
{
    private readonly List<VideoModel> _videoList = [];
    public VideoModel? VideoItem { get; set; }
    public BindableCollection<VideoModel> Videos { get; private set; } = [];
    private static readonly object VideoAddLock = new();
    private Dictionary<int, MediaSourceModel>? _mediaSourceDict;
    public BindableCollection<MediaSourceModel> MediaSources { get; set; } = [];
    private MediaSourceModel? _mediaSourceItem;

    public MediaSourceModel? MediaSourceItem
    {
        get => _mediaSourceItem;
        set
        {
            _mediaSourceItem = value;
            MediaSourceItemChangedAsync(value);
        }
    }


    public string? KeyWord { get; set; }
    public int PageSize { get; set; } = 20;
    public int Total { get; set; } = 30;
    private int _pageIndex;

    public int PageIndex
    {
        get => _pageIndex;
        set
        {
            _pageIndex = value;
            PageIndexChangedAsync(value);
        }
    }

    private Task PageIndexChangedAsync(int pageIndex)
    {
        return Task.Run(() =>
        {
            Execute.PostToUIThreadAsync(() =>
            {
                Videos = PageIndex == 1
                    ? [.. _videoList.Take(PageSize)]
                    : [.. _videoList.Skip((PageIndex - 1) * PageSize).Take(PageSize)];
            });
        });
    }

    protected override void OnInitialActivate()
    {
        base.OnInitialActivate();
        MediaSources = [.. appService.GetMediaSources()];
        _mediaSourceDict = MediaSources.ToDictionary(x => x.Id, v => v);


        if (!string.IsNullOrEmpty(KeyWord)) TaskSearch(KeyWord);
    }

    private Task MediaSourceItemChangedAsync(MediaSourceModel? model)
    {
        return Task.Run(() =>
        {
            Execute.PostToUIThreadAsync(() => { Videos = [.. _videoList.Where(x => x.VodSourceID == model.Id)]; });
        });
    }

    private async void AddVideoData(int sourceId, string keyWord)
    {
        var req = new ReqQryVideoPara { SourceId = sourceId, KeyWord = keyWord, AcName = "videolist" };
        var rspData = await apiService.ReqQryVideosAsync(req);
        if (rspData?.Videos is not { Count: > 0 }) return;
        rspData.Videos.ForEach(x =>
        {
            x.VodSourceID = sourceId;
            if (_mediaSourceDict != null && _mediaSourceDict.TryGetValue(x.VodSourceID, out var model))
                x.VodSourceTitle = model.Title;
        });
        lock (VideoAddLock)
        {
            _videoList.AddRange(rspData.Videos);
            Total = _videoList.Count;
            if (Total <= PageSize) PageIndexChangedAsync(1);
        }
    }

    private void TaskSearch(string keyWord)
    {
        var cancellationSource = new CancellationTokenSource();
        var options = new ParallelOptions
        {
            // 最大并行度，并行的任务有几个
            MaxDegreeOfParallelism = 2,
            CancellationToken = cancellationSource.Token
        };

        if (_mediaSourceDict is not { Count: > 0 }) return;
        //  清空列表数据
        _videoList.Clear();

        //  并行查询
        Parallel.For(0, _mediaSourceDict.Count, options,
            x => { AddVideoData(_mediaSourceDict.Keys.ElementAt(x), keyWord); });
    }

    public Task PlayAsync(VideoModel o)
    {
        return Task.Run(async () =>
        {
            var req = new ReqQryVideoDetailPara { SourceId = o.VodSourceID, VodIds = $"{o.VodId}", AcName = "detail" };
            var detail = await apiService.ReqQryVideoDetailsAsync(req);
            await Execute.PostToUIThreadAsync(() =>
            {
                var playVm = container.Get<PlayerViewModel>();

                //  播放列表
                var para = mapper.Map<ThinkPhpVideoParsingPara>(detail);
                playVm.PlayDict = sourceProtocolAdapter.GetPlayDict(para);
                windowManager.ShowWindow(playVm);
            });
        });
    }

    public void BackTo()
    {
        eventAggregator.Publish(new ScreenChangedMessage { ViewModel = "VideoViewModel" });
    }
}